package com.lxm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lxm.common.contants.FollowConstants;
import com.lxm.common.contants.RedisExpire;
import com.lxm.common.tools.UserHolder;
import com.lxm.dto.Result;
import com.lxm.entity.Follow;
import com.lxm.entity.Login;
import com.lxm.mapper.FollowDao;
import com.lxm.service.FollowService;
import com.lxm.service.LoginService;
import com.lxm.vo.FansVO;
import com.lxm.vo.FollowVO;
import jakarta.annotation.Resource;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 关注表 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2024-10-02
 */
@Service
public class FollowServiceImpl extends ServiceImpl<FollowDao, Follow> implements FollowService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private LoginService loginService;


    @Override
    public Result followUser(Long followeeId) {
        Long userId = UserHolder.getUser().getUserId();

        if (userId.equals(followeeId)) {
            return Result.fail(FollowConstants.FOLLOW_ME_FAIL);
        }

        //判断是否已经关注
        if (exists(new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFanId, userId)
                .eq(Follow::getBloggerId, followeeId))) {
            return Result.fail(FollowConstants.FOLLOW_USER_FAIL);
        }

        //保存数据
        Follow follow = new Follow();
        follow.setFanId(userId);
        follow.setBloggerId(followeeId);
        save(follow);
        stringRedisTemplate.opsForSet()
                .add(FollowConstants.FOLLOW_ID + userId, followeeId.toString());
        //新关注一次用户刷新一次过期时间
        stringRedisTemplate
                .expire(FollowConstants.FOLLOW_ID + userId,
                        RedisExpire.FOLLOWEE_ID_SET_EXPIRE, TimeUnit.MINUTES);
        return Result.ok(FollowConstants.FOLLOW_SUCCESS);
    }

    @Override
    public Result checkFollow(Long followeeId) {
        Long userId = UserHolder.getUser().getUserId();
        //Redis中获取该用户所有关注的博主id
        //Collection算是所有容器类对象都继承了的一个大父类
        boolean isExist = BooleanUtil.isTrue(stringRedisTemplate.opsForSet()
                .isMember(FollowConstants.FOLLOW_ID + userId, followeeId.toString()));
        if (isExist) return Result.ok(FollowConstants.FOLLOW);
        //Redis中检查了，SQL复查,这里让SQL不返回数据进一步优化性能。
        boolean followExists = exists(new LambdaQueryWrapper<Follow>()
                .eq(Follow::getBloggerId, followeeId)
                .eq(Follow::getFanId, userId));
        //前端接收就直接分类了，不用if-else在进行判断
        if (!followExists) return Result.fail(FollowConstants.NOFOLLOW);
        return Result.ok();
    }

    //获取所有自己关注的博主的id
    @Override
    public Result getAllFolloweeId() {
        Long userId = UserHolder.getUser().getUserId();
        //获取所有自己关注的博主id
        List<Long> FolloweeIdList = lambdaQuery().eq(Follow::getFanId, userId)
                //只返回博主id，提高性能
                .select(Follow::getBloggerId)
                .list()
                .stream()
                .map(Follow::getBloggerId)
                .toList();
        //判断是否为空
        if (FolloweeIdList.isEmpty()) {
            return Result.fail(FollowConstants.NO_ONE_FOLLOW);
        }
        //将关注了的博主id保存到redis中
        FolloweeIdList.forEach(ID -> stringRedisTemplate.opsForSet()
                .add(FollowConstants.FOLLOW_ID + userId, ID.toString()));

        stringRedisTemplate
                .expire(FollowConstants.FOLLOW_ID + userId,
                        RedisExpire.FOLLOWEE_ID_SET_EXPIRE, TimeUnit.MINUTES);
        return Result.ok();
    }

    //前端必须确保一件事，就是发送取消关注的按钮，
    // 只有在用户已关注的情况才会显示，才能发送取消关注请求
    @Override
    public Result deleteFollow(Long followeeId) {
        Long userId = UserHolder.getUser().getUserId();
        boolean isRemove = remove(new LambdaQueryWrapper<Follow>()
                .eq(Follow::getFanId, userId)
                .eq(Follow::getBloggerId, followeeId));
        //判断是否删除成功
        // 这里即便是因为传入请求取关的博主id在数据表中fanId和blogerId一一对应查询不存在，也返回false
        if (!isRemove) return Result.fail(FollowConstants.UNFOLLOW_FAIL);
        //删除redis中的数据
        stringRedisTemplate.opsForSet()
                .remove(FollowConstants.FOLLOW_ID + userId, followeeId.toString());

        return Result.ok(FollowConstants.UNFOLLOW_SUCCESS);
    }

    @Override
    public Result getUserFollowList(Long currentId, Long userId) {
        if (userId == null) userId = UserHolder.getUser().getUserId();
        //获取当前用户关注分页当前页数据
        List<Follow> followList = lambdaQuery()
                .eq(Follow::getFanId, userId)
                .orderByDesc(Follow::getCreateTime)
                .page(new Page<>(currentId, FollowConstants.FOLLOW_PAGE_SIZE))
                .getRecords();
        if (CollUtil.isEmpty(followList)) {
            //如果为空直接返回回去
            return Result.ok(followList);
        }
        List<FollowVO> followVOList = followList
                .stream()
                .map(this::getFollowVO)
                .collect(Collectors.toList());
        return Result.ok(followVOList);
    }

    @Override
    public Result getUserFanList(Long currentId, Long userId) {
        if (userId == null) userId = UserHolder.getUser().getUserId();
        //获取当前用户粉丝分页当前页数据
        List<Follow> followList = lambdaQuery()
                .eq(Follow::getBloggerId, userId)
                .orderByDesc(Follow::getCreateTime)
                .page(new Page<>(currentId, FollowConstants.FOLLOW_PAGE_SIZE))
                .getRecords();
        //判断是否为空
        if (CollUtil.isEmpty(followList)) {
            //如果为空直接返回回去
            return Result.ok(followList);
        }
        //转换为VO
        List<FansVO> fansVOList = followList
                .stream()
                .map(this::getFansVO)
                .collect(Collectors.toList());
        return Result.ok(fansVOList);
    }


    //封装VO，用来封装博主信息
    @NotNull
    private FollowVO getFollowVO(Follow follow) {
        //获取博主信息
        Login blogInfo = loginService.getUserInfoLogin(follow.getBloggerId());
        //封装VO
        FollowVO followVO = BeanUtil.toBean(blogInfo, FollowVO.class);
        //设置初次关注时间
        followVO.setCreateTime(follow.getCreateTime());
        //设置被用户关注的博主id
        followVO.setBlogerId(follow.getBloggerId());
        return followVO;
    }

    @NotNull
    private FansVO getFansVO(Follow follow) {
        //根据粉丝ID获取粉丝信息
        Login fansInfo = loginService.getUserInfoLogin(follow.getFanId());
        //封装VO
        FansVO fansVO = BeanUtil.toBean(fansInfo, FansVO.class);
        //设置初次关注时间
        fansVO.setCreateTime(follow.getCreateTime());
        //设置关注自己的粉丝id
        fansVO.setFanId(follow.getFanId());
        return fansVO;
    }
}
